home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / lib / ansi / strtoul.c < prev    next >
C/C++ Source or Header  |  1990-07-20  |  2KB  |  93 lines

  1. /* strtoul.c                        ANSI 4.10.1.6
  2.  *    unsigned long int strtoul(const char *nptr, char **endptr, int base);
  3.  *
  4.  *    Converts a numeric string, in various bases, to an unsigned long.
  5.  */
  6.  
  7. #include <lib.h>
  8. #include <ctype.h>
  9. #include <errno.h>
  10. #include <limits.h>
  11. #include <stdlib.h>
  12.  
  13. #ifdef strtoul
  14. #undef strtoul
  15. #endif
  16.  
  17. PUBLIC unsigned long int strtoul(nptr, endptr, base)
  18. _CONST char *nptr;
  19. char **endptr;
  20. int base;
  21. {
  22.   register int c;
  23.   unsigned long int result = 0L;
  24.   unsigned long int limit;
  25.   int negative = 0;
  26.   int overflow = 0;
  27.   int saw_a_digit = 0;            /* it's not a number without a digit */
  28.  
  29.   if (endptr != (char **) NULL)        /* set up default final pointer */
  30.     *endptr = nptr;
  31.  
  32.   while ((c = *nptr) && isspace(c))    /* skip leading white space */
  33.     ++nptr;
  34.  
  35.   if (c == '+' || c == '-') {        /* handle signs */
  36.     negative = (c == '-');
  37.     ++nptr;
  38.   }
  39.  
  40.   if (base == 0) {            /* determine base if unknown */
  41.     base = 10;
  42.     if (*nptr == '0') {
  43.         base = 8;
  44.         ++nptr;
  45.         if ((c = *nptr) == 'x' || c == 'X') {
  46.             base = 16;
  47.             ++nptr;
  48.         }
  49.     }
  50.   }
  51.   else
  52.   if (base == 16 && *nptr == '0') {    /* discard 0x/0X prefix if hex */
  53.     ++nptr;
  54.     if ((c = *nptr == 'x') || c == 'X')
  55.         ++nptr;
  56.   }
  57.  
  58.   limit = ULONG_MAX / base;        /* ensure no overflow */
  59.  
  60.   --nptr;                /* convert the number */
  61.   while ((c = *++nptr) != 0) {
  62.     if (isdigit(c))
  63.         c -= '0';
  64.     else
  65.         c -= isupper(c) ? ('A' - 10) : ('a' - 10);
  66.     if (c < 0 || c >= base)
  67.         break;
  68.     saw_a_digit = 1;
  69.     if (result > limit)
  70.         overflow = 1;
  71.     if (!overflow) {
  72.         result = base * result;
  73.         if (c > ULONG_MAX - result)
  74.             overflow = 1;
  75.         else    
  76.             result += c;
  77.     }
  78.   }
  79.   if (!saw_a_digit)
  80.     return 0;
  81.  
  82.   if (negative && !overflow)    /* BIZARRE, but ANSI says we should do this! */
  83.     result = 0L - result;
  84.   if (overflow) {
  85.     errno = ERANGE;
  86.     result = ULONG_MAX;
  87.   }
  88.  
  89.   if (endptr != (char **) NULL)        /* record good final pointer */
  90.     *endptr = nptr;
  91.   return result;
  92. }
  93.